﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Xml;

namespace ConfigMeister
{
    public partial class Form1 : Form
    {
        private List<Light> _lightBucket;
        private List<RenderObject> _objectBucket;

        public Form1()
        {
            InitializeComponent();
            //MaterialBucket.Add(new Material());
            _objectBucket = new List<RenderObject>();
            _lightBucket = new List<Light>();
            comboBox1.SelectedIndex = 0;
        }

        private void RefreshLists()
        {
            listBox1.Items.Clear();
            listBox2.Items.Clear();

            foreach (Light val in _lightBucket)
            {
                listBox2.Items.Add(val.Name);
            }

            foreach (RenderObject val in _objectBucket)
            {
                listBox1.Items.Add(val.Name);
            }
        }

        private void button3_Click(object sender, EventArgs e)
        {
            MaterialBox box = new MaterialBox();
            box.ShowDialog();
        }

        private void button4_Click(object sender, EventArgs e)
        {
            SettingsBox box = new SettingsBox();
            box.ShowDialog();
        }

        private void button6_Click(object sender, EventArgs e)
        {
            LightBox box = new LightBox(new Light());
            if(box.ShowDialog() == DialogResult.OK)
            {
                _lightBucket.Add(box.Result);
                RefreshLists();
            }
        }

        private void listBox2_DoubleClick(object sender, EventArgs e)
        {
            if(listBox2.SelectedIndex == -1) return;

            for(int i=0; i<_lightBucket.Count; i++)
            {
                if(_lightBucket[i].Name == listBox2.SelectedItem.ToString())
                {
                    LightBox box = new LightBox(_lightBucket[i]);
                    if (box.ShowDialog() == DialogResult.OK)
                    {
                        _lightBucket[i] = box.Result;
                        RefreshLists();
                    }

                }
            }
        }

        private void button7_Click(object sender, EventArgs e)
        {
            if (listBox2.SelectedIndex == -1) return;

            for (int i = 0; i < _lightBucket.Count; i++)
            {
                if (_lightBucket[i].Name == listBox2.SelectedItem.ToString())
                {
                    _lightBucket.RemoveAt(i);
                    RefreshLists();
                }
            }
        }

        private void button1_Click(object sender, EventArgs e)
        {
            if(comboBox1.SelectedIndex == 0)
            {
                SphereBox box = new SphereBox(new Sphere());
                if (box.ShowDialog() == DialogResult.OK)
                {
                    _objectBucket.Add(box.Result);
                    RefreshLists();
                }
            }
            else
            {
                TriangleBox box = new TriangleBox(new Triangle());
                if (box.ShowDialog() == DialogResult.OK)
                {
                    _objectBucket.Add(box.Result);
                    RefreshLists();
                }
            }
        }

        private void button2_Click(object sender, EventArgs e)
        {
            if(listBox1.SelectedIndex == -1) return;

            for (int i = 0; i < _objectBucket.Count; i++)
            {
                if (_objectBucket[i].Name == listBox1.SelectedItem.ToString())
                {
                    _objectBucket.RemoveAt(i);
                    RefreshLists();
                }
            }
        }

        private void listBox1_DoubleClick(object sender, EventArgs e)
        {
            if (listBox1.SelectedIndex == -1) return;
            if (listBox1.SelectedItem == null) return;

            for (int i = 0; i < _objectBucket.Count; i++)
            {
                if (_objectBucket[i].Name == listBox1.SelectedItem.ToString())
                {
                    string temp = _objectBucket[i].GetType().ToString();
                    if (temp == "ConfigMeister.Sphere")
                    {
                        SphereBox box = new SphereBox((Sphere)_objectBucket[i]);
                        if (box.ShowDialog() == DialogResult.OK)
                        {
                            _objectBucket[i] = box.Result;
                            RefreshLists();
                        }
                    }
                    else
                    {
                        TriangleBox box = new TriangleBox((Triangle)_objectBucket[i]);
                        if (box.ShowDialog() == DialogResult.OK)
                        {
                            _objectBucket[i] = box.Result;
                            RefreshLists();
                        }
                    }

                }
            }
        }

        private void WriteColor(Color c, XmlTextWriter writer)
        {
            writer.WriteStartElement("color");
            double temp;

            temp = (double)c.R/255;
            writer.WriteElementString("R", temp.ToString(CultureInfo.InvariantCulture));

            temp = (double)c.G / 255;
            writer.WriteElementString("G", temp.ToString(CultureInfo.InvariantCulture));

            temp = (double)c.B / 255;
            writer.WriteElementString("B", temp.ToString(CultureInfo.InvariantCulture));

            temp = (double)c.A / 255;
            writer.WriteElementString("A", temp.ToString(CultureInfo.InvariantCulture));

            writer.WriteEndElement();
        }

        private void WriteMaterial(string name, XmlTextWriter writer)
        {
            Material mat = MaterialBucket.Get(name);

            writer.WriteStartElement("material");

            writer.WriteElementString("name", mat.Name);

            writer.WriteStartElement("diffuse");
            WriteColor(mat.Diffuse, writer);
            writer.WriteEndElement();

            writer.WriteElementString("texture", mat.Texture);

            writer.WriteStartElement("ambient");
            WriteColor(mat.Ambient, writer);
            writer.WriteEndElement();

            writer.WriteStartElement("specular");
            WriteColor(mat.Specular, writer);
            writer.WriteEndElement();

            writer.WriteElementString("specularIntesity", mat.specularIntesity.ToString(CultureInfo.InvariantCulture));
            writer.WriteElementString("glosiness", mat.Glossiness.ToString(CultureInfo.InvariantCulture));
            writer.WriteElementString("soften", mat.Soften.ToString(CultureInfo.InvariantCulture));
            writer.WriteElementString("twoSided", mat.TwoSided.ToString(CultureInfo.InvariantCulture));
            writer.WriteElementString("shadedSurfBalckenssCoef", mat.ShadedSurfBlacknessCoef.ToString(CultureInfo.InvariantCulture));
            writer.WriteElementString("shadingAlgorithm", mat.ShadingAlgorithm.ToString(CultureInfo.InvariantCulture));

            writer.WriteEndElement();
        }

        private void WriteOptions()
        {
            XmlTextWriter writer = new XmlTextWriter("renderoptions.xml", Encoding.UTF8);
            writer.Formatting = Formatting.Indented;
            writer.IndentChar = '\t';
            writer.Indentation = 1;

            writer.WriteStartDocument();

            writer.WriteStartElement("renderoptions");

            writer.WriteElementString("width", SceneSettings.Width.ToString(CultureInfo.InvariantCulture));
            writer.WriteElementString("height", SceneSettings.Height.ToString(CultureInfo.InvariantCulture));
            writer.WriteElementString("antialiasing", SceneSettings.Antialising.ToString(CultureInfo.InvariantCulture));
            writer.WriteElementString("antialiasingMultiplier", SceneSettings.AntiMultiplier.ToString(CultureInfo.InvariantCulture));
            writer.WriteElementString("lights", SceneSettings.Lights.ToString(CultureInfo.InvariantCulture));
            writer.WriteElementString("shades", SceneSettings.Shades.ToString(CultureInfo.InvariantCulture));
            writer.WriteElementString("reflections", SceneSettings.Reflections.ToString(CultureInfo.InvariantCulture));
            writer.WriteElementString("reflectionsPrecision", SceneSettings.ReflectionsPrecision.ToString(CultureInfo.InvariantCulture));
            writer.WriteElementString("refractions", SceneSettings.Refractions.ToString(CultureInfo.InvariantCulture));
            writer.WriteElementString("refracionDepth", SceneSettings.RefractionDepth.ToString(CultureInfo.InvariantCulture));
            writer.WriteElementString("FOV", SceneSettings.Fov.ToString(CultureInfo.InvariantCulture));
            writer.WriteElementString("cameraType", SceneSettings.CameraType.ToString(CultureInfo.InvariantCulture));
            writer.WriteElementString("clipping", SceneSettings.Clipping.ToString(CultureInfo.InvariantCulture));
            writer.WriteElementString("sceneDivision", SceneSettings.SceneDivision.ToString(CultureInfo.InvariantCulture));
            writer.WriteElementString("divisionAlgorithm", SceneSettings.DivisionAlgorithm.ToString(CultureInfo.InvariantCulture));
            writer.WriteElementString("cornelBox", SceneSettings.CornellBox.ToString(CultureInfo.InvariantCulture));

            writer.Flush();

            writer.WriteStartElement("backgroundMaterial");
            WriteMaterial(SceneSettings.BgMaterial,writer);
            writer.WriteEndElement();

            writer.Flush();

            writer.WriteElementString("pixelAspectRatio", SceneSettings.PixelAspect.ToString());

            writer.WriteEndElement();

            writer.WriteEndDocument();

            writer.Flush();
        }

        private void WritePoint(Point3 p, XmlTextWriter writer, string text)
        {
            writer.WriteStartElement(text);

            writer.WriteElementString("X", p.X.ToString(CultureInfo.InvariantCulture));
            writer.WriteElementString("Y", p.Y.ToString(CultureInfo.InvariantCulture));
            writer.WriteElementString("Z", p.Z.ToString(CultureInfo.InvariantCulture));

            writer.WriteEndElement();
        }

        private void WriteCoord(TexCoords tex, XmlTextWriter writer)
        {
            writer.WriteStartElement("texcoord");

            writer.WriteElementString("U", tex.U.ToString(CultureInfo.InvariantCulture));
            writer.WriteElementString("V", tex.V.ToString(CultureInfo.InvariantCulture));

            writer.WriteEndElement();
        }

        private void WriteCamera()
        {
            XmlTextWriter writer = new XmlTextWriter("camera.xml", Encoding.UTF8);
            writer.Formatting = Formatting.Indented;
            writer.IndentChar = '\t';
            writer.Indentation = 1;

            writer.WriteStartDocument();
            writer.WriteStartElement("camera");

            writer.WriteStartElement("camPosition");
            WritePoint(SceneSettings.CameraPos,writer,"point");
            writer.WriteEndElement();

            writer.WriteStartElement("gridPosition");
            WritePoint(SceneSettings.CameraTarget, writer, "point");
            writer.WriteEndElement();

            writer.WriteStartElement("Up");
            WritePoint(SceneSettings.CameraTarget, writer, "vector3");
            writer.WriteEndElement();

            writer.WriteEndElement();
            writer.WriteEndDocument();
            writer.Flush();
        }

        private void WriteLight(Light li, XmlTextWriter writer)
        {
            writer.WriteStartElement("light");

            writer.WriteStartElement("ambient");
            WriteColor(li.Ambient,writer);
            writer.WriteEndElement();
            writer.WriteElementString("multiplyier", li.Multiplier.ToString(CultureInfo.InvariantCulture));
            writer.WriteElementString("decayInverseParam", li.DecayInverseParam.ToString(CultureInfo.InvariantCulture));
            writer.WriteElementString("decayInverseSqrParam", li.DecayInverseSqrParam.ToString(CultureInfo.InvariantCulture));
            writer.WriteElementString("ambienCoef", li.AmbientCoef.ToString(CultureInfo.InvariantCulture));
            
            writer.Flush();

            writer.WriteStartElement("position");
            WritePoint(li.Pos, writer, "point");
            writer.WriteEndElement();

            writer.WriteStartElement("destination");
            WritePoint(li.Pos, writer, "point");
            writer.WriteEndElement();

            writer.Flush();

            writer.WriteElementString("isAmbient", li.IsAmbient.ToString(CultureInfo.InvariantCulture));
            writer.WriteElementString("castShadow", li.CastShadow.ToString(CultureInfo.InvariantCulture));
            writer.WriteElementString("decay", li.Decay.ToString(CultureInfo.InvariantCulture));
            writer.WriteElementString("targeted", li.Targeted.ToString(CultureInfo.InvariantCulture));

            writer.WriteEndElement();

            writer.Flush();
        }

        private void WriteObject(Sphere obj, XmlTextWriter writer)
        {
            writer.WriteStartElement("sphere");

            writer.WriteStartElement("surfacematerial");
            WriteMaterial(obj.Material,writer);
            writer.WriteEndElement();
            writer.Flush();

            writer.WriteElementString("name",obj.Name);
            writer.WriteStartElement("position");
            WritePoint(obj.Pos, writer, "point");
            writer.WriteEndElement();
            writer.Flush();

            writer.WriteElementString("radius", obj.Radius.ToString(CultureInfo.InvariantCulture));

            writer.WriteEndElement();
            writer.Flush();
        }

        private void WriteObject(Triangle obj, XmlTextWriter writer)
        {
            writer.WriteStartElement("triangle");

            writer.WriteStartElement("surfacematerial");
            WriteMaterial(obj.Material, writer);
            writer.WriteEndElement();
            writer.Flush();

            writer.WriteElementString("name", obj.Name);
            writer.WriteElementString("multiplyier", obj.Multiplier.ToString(CultureInfo.InvariantCulture));
            writer.Flush();
            writer.WriteStartElement("pointA");
            WritePoint(obj.PointA, writer, "point");
            WriteCoord(obj.CoordA, writer);
            writer.WriteEndElement();
            writer.Flush();
            writer.WriteStartElement("pointB");
            WritePoint(obj.PointB, writer, "point");
            WriteCoord(obj.CoordB, writer);
            writer.WriteEndElement();
            writer.Flush();
            writer.WriteStartElement("pointC");
            WritePoint(obj.PointC, writer, "point");
            WriteCoord(obj.CoordC, writer);
            writer.WriteEndElement();
            writer.Flush();

            writer.WriteEndElement();
            writer.Flush();
        }

        private void WriteScene()
        {
            XmlTextWriter writer = new XmlTextWriter("scena.xml", Encoding.UTF8);
            writer.Formatting = Formatting.Indented;
            writer.IndentChar = '\t';
            writer.Indentation = 1;

            writer.WriteStartDocument();
            writer.WriteStartElement("scene");

            int spheres = 0, triangles = 0;

            foreach (RenderObject val in _objectBucket)
            {
                string temp = val.GetType().ToString();
                if (temp == "ConfigMeister.Sphere")
                    spheres++;
                else triangles++;
            }

            writer.WriteAttributeString("lightsCount", _lightBucket.Count.ToString());
            writer.WriteAttributeString("sphereCount", spheres.ToString());
            writer.WriteAttributeString("triangleCount", triangles.ToString());

            writer.Flush();
            writer.WriteStartElement("lights");
            foreach (Light val in _lightBucket)
            {
                WriteLight(val,writer);
            }
            writer.WriteEndElement();

            writer.WriteStartElement("objects");
            foreach (RenderObject val in _objectBucket)
            {
                if (val.GetType().ToString() == "ConfigMeister.Sphere")
                    WriteObject((Sphere) val, writer);
                else
                {
                    WriteObject((Triangle)val, writer);
                }
            }
            writer.WriteEndElement();

            writer.WriteEndElement();
            writer.Flush();

            writer.WriteEndDocument();
            writer.Flush();
        }

        private void button5_Click(object sender, EventArgs e)
        {
            WriteOptions();
            WriteCamera();
            WriteScene();

            const string imageName = "output.bmp";

            Process render = Process.Start("Rendermeister.exe", "-r renderoptions.xml -s scena.xml -c camera.xml -o " + imageName);

            render.WaitForExit();

            MessageBox.Show("Wyrenderowano do pliku " + imageName);

            Image image = new Bitmap(imageName);

            ImageBox box = new ImageBox(image);

            box.ShowDialog();
        }
    }
}
